package pl.edu.pb.wi.cookbook.controller;

import java.util.Arrays;
import java.util.List;
import java.util.logging.Logger;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import pl.edu.pb.wi.cookbook.entity.Cookbook;
import pl.edu.pb.wi.cookbook.entity.Recipe;
import pl.edu.pb.wi.cookbook.entity.User;
import pl.edu.pb.wi.cookbook.form.AddToCookbookForm;
import pl.edu.pb.wi.cookbook.form.NewCookbookForm;
import pl.edu.pb.wi.cookbook.service.CookbookService;
import pl.edu.pb.wi.cookbook.service.RecipeService;
import pl.edu.pb.wi.cookbook.session.UserSession;

import com.googlecode.objectify.Key;

@Controller
@RequestMapping("/user/cookbook")
public class UserCookbookController {
    private static final Logger log = Logger
            .getLogger(UserCookbookController.class.getName());

    private CookbookService cookbookService;
    private UserSession userSession;
    private RecipeService recipeService;

    @Autowired
    public UserCookbookController(CookbookService cookbookService,
            UserSession userSession, RecipeService recipeService) {
        this.cookbookService = cookbookService;
        this.userSession = userSession;
        this.recipeService = recipeService;
    }

    @RequestMapping(value = "create", method = RequestMethod.GET)
    public String create(Model model) {
        model.addAttribute("form", new NewCookbookForm());

        return "user/cookbook/create";
    }

    @RequestMapping(value = "create", method = RequestMethod.POST)
    public String create(@ModelAttribute("form")
    @Valid
    NewCookbookForm form, BindingResult results, Model model) {
        String returnPath = "user/cookbook/create";

        if (form != null
                && !cookbookService.isNameUniqueInUserProfile(
                        userSession.getUser(), form.getName()))
            results.addError(new FieldError("form", "name",
                    "W twoim profilu już istnieje książka o podanej nazwie."));

        if (results.hasErrors()) {
            return returnPath;
        }

        try {
            cookbookService.createCookbook(userSession.getUser(),
                    form.getName(), form.getDescription(), form.getIsPrivate());

            model.addAttribute(
                    "successMsgs",
                    Arrays.asList(new String[] { String
                            .format("Książka kucharska '%s' została dodana do twojego profilu.",
                                    form.getName()) }));
        } catch (Exception e) {
            log.info(String.format("Problem with login form. Exception: %s",
                    e.getMessage()));

            model.addAttribute(
                    "errorMsgs",
                    Arrays.asList(new String[] { "Wystąpił błąd. Spróbuj ponownie." }));

            returnPath = "message";
        }

        return returnPath;
    }

    @RequestMapping(value = "edit/{id}", method = RequestMethod.GET)
    public String edit(@PathVariable("id")
    long id, Model model) {
        String returnPath = "message";

        try {
            Cookbook book = cookbookService.getCookBook(id);
            if (book != null) {
                if (book.getAuthor().getId() == userSession.getUser().getId()) {
                    model.addAttribute("id", id);
                    model.addAttribute("form",
                            conveCookbookToCookbookForm(book));

                    returnPath = "user/cookbook/edit";
                } else {
                    model.addAttribute("errorMsgs", Arrays
                            .asList(new String[] { "Nieprawidłowa książka." }));
                }
            } else {
                model.addAttribute("errorMsgs", Arrays
                        .asList(new String[] { "Nieprawidłowa książka." }));
            }
        } catch (Exception e) {
            log.info(String.format(
                    "Problem with edit cookbook get. Exception: %s",
                    e.getMessage()));

            model.addAttribute(
                    "errorMsgs",
                    Arrays.asList(new String[] { "Wystąpił błąd. Spróbuj ponownie." }));
        }

        return returnPath;
    }

    @RequestMapping(value = "edit/{id}", method = RequestMethod.POST)
    public String edit(@ModelAttribute("form")
    @Valid
    NewCookbookForm form, BindingResult results, Model model,
            @PathVariable("id")
            long id) {
        String returnPath = "message";

        if (results.hasErrors()) {
            return "user/cookbook/edit";
        }

        try {
            Cookbook book = cookbookService.getCookBook(id);

            if (book != null) {
                if (book.getAuthor().getId() == userSession.getUser().getId()) {
                    Cookbook updatedc = converCookbookFormToCookbook(form, book);
                    cookbookService.updateCookbook(updatedc);

                    model.addAttribute("successMsgs",
                            Arrays.asList(new String[] { "Zapisano zmiany." }));

                    returnPath = "forward:/user/cookbook/management/list";
                } else {
                    model.addAttribute("errorMsgs", Arrays
                            .asList(new String[] { "Nieprawidłowa książka." }));
                }
            } else {
                model.addAttribute("errorMsgs", Arrays
                        .asList(new String[] { "Nieprawidłowa książka." }));
            }
        } catch (Exception e) {
            log.info(String.format(
                    "Problem with NewRecipeForm form. Exception: %s",
                    e.getMessage()));

            model.addAttribute(
                    "errorMsgs",
                    Arrays.asList(new String[] { "Wystąpił błąd. Spróbuj ponownie." }));
        }

        return returnPath;
    }

    private NewCookbookForm conveCookbookToCookbookForm(Cookbook c) {
        NewCookbookForm form = new NewCookbookForm();

        form.setIsPrivate(c.isPrivate());
        form.setName(c.getName());
        form.setDescription(c.getDescription());

        return form;
    }

    @RequestMapping(value = "recipe/add/{recipeId}", method = RequestMethod.POST)
    public String add(@ModelAttribute("form")
    @Valid
    AddToCookbookForm form, BindingResult results, Model model,
            @PathVariable("recipeId")
            long recipeId) {
        String returnPath = "redirect:/recipe/list";

        if (results.hasErrors()) {
            return "recipe/show";
        }

        try {
            Recipe rec = recipeService.getRecipe(recipeId);

            if (rec != null) {
                Cookbook book = cookbookService.getCookBook(form
                        .getCookbookId());

                if (book != null) {
                    if (cookbookService.isBookWithoutRecipe(book, rec)) {
                        cookbookService.addRecipeToCookbook(book, rec);

                        model.addAttribute(
                                "successMsgs",
                                Arrays.asList(new String[] { String
                                        .format("Przepis '%s' został pomyślnie dodany do książki '%s'.",
                                                rec.getName(), book.getName()) }));

                        returnPath = String.format("forward:/recipe/%s",
                                rec.getId());
                    } else {
                        model.addAttribute(
                                "errorMsgs",
                                Arrays.asList(new String[] { "Podana książka już posiada ten przepis." }));

                        returnPath = String.format("forward:/recipe/%s",
                                rec.getId());
                    }
                } else {
                    model.addAttribute("errorMsgs", Arrays
                            .asList(new String[] { "Nieprawidłowa książka." }));

                    returnPath = String.format("forward:/recipe/%s",
                            rec.getId());
                }
            } else {
                model.addAttribute("errorMsgs", Arrays
                        .asList(new String[] { "Nieprawidłowy przepis." }));

                returnPath = "message";
            }
        } catch (Exception e) {
            log.info(String.format(
                    "Problem with NewRecipeForm form. Exception: %s",
                    e.getMessage()));

            model.addAttribute(
                    "errorMsgs",
                    Arrays.asList(new String[] { "Wystąpił błąd. Spróbuj ponownie." }));

            returnPath = "message";
        }

        return returnPath;
    }

    @RequestMapping("delete/{id}")
    public String delete(@PathVariable("id")
    Long id, Model model) {
        String returnPath = "forward:/user/cookbook/management/list";

        try {
            Cookbook cook = cookbookService.getCookBook(id);
            if (cook != null) {
                if (cook.getAuthor().getId() == userSession.getUser().getId()) {
                    String name = cook.getName();
                    cookbookService.removeCookbook(cook);

                    model.addAttribute("successMsgs", Arrays
                            .asList(new String[] { String.format(
                                    "Przepis '%s' usunięto pomyślnie", name) }));
                } else {
                    model.addAttribute("errorMsgs", Arrays
                            .asList(new String[] { "Nieprawidłowy przepis." }));
                }
            } else {
                model.addAttribute("errorMsgs", Arrays
                        .asList(new String[] { "Nieprawidłowy przepis." }));
            }
        } catch (Exception e) {
            log.info(String.format(
                    "Problem with deleteform form. Exception: %s",
                    e.getMessage()));

            model.addAttribute(
                    "errorMsgs",
                    Arrays.asList(new String[] { "Wystąpił błąd. Spróbuj ponownie." }));

            returnPath = "message";
        }

        return returnPath;
    }

    private Cookbook converCookbookFormToCookbook(NewCookbookForm form,
            Cookbook book) {
        book.setAuthor((new Key<User>(User.class, userSession.getUser().getId())));
        book.setPrivate(form.getIsPrivate());
        book.setName(form.getName());
        book.setDescription(form.getDescription());
        return book;
    }

    @RequestMapping("deleterecipe/{id}/{cid}")
    public String delete(@PathVariable("id")
    long id, @PathVariable("cid")
    long cid, Model model) {
        String returnPath = "message";

        try {
            Recipe rec = recipeService.getRecipe(id);
            Cookbook cook = cookbookService.getCookBook(cid);
            if (rec != null && cook != null) {
                if (rec.getAuthor().getId() == userSession.getUser().getId()) {
                    String name = rec.getName();
                    cookbookService.removeRecipeFromCookbook(cook, rec);

                    model.addAttribute("successMsgs", Arrays
                            .asList(new String[] { String.format(
                                    "Przepis '%s' usunięto pomyślnie", name) }));

                    returnPath = "forward:/user/cookbook/list";
                } else {
                    model.addAttribute("errorMsgs", Arrays
                            .asList(new String[] { "Nieprawidłowy przepis." }));
                }
            } else {
                model.addAttribute("errorMsgs", Arrays
                        .asList(new String[] { "Nieprawidłowy przepis." }));
            }
        } catch (Exception e) {
            log.info(String.format(
                    "Problem with deleteform form. Exception: %s",
                    e.getMessage()));

            model.addAttribute(
                    "errorMsgs",
                    Arrays.asList(new String[] { "Wystąpił błąd. Spróbuj ponownie." }));
        }

        return returnPath;
    }

    @RequestMapping("list")
    public String list(Model model) {
        try {
            Cookbook book = cookbookService.getFirstCookbook();

            if (book != null) {
                List<Cookbook> cook = cookbookService
                        .getUsersCookbooks(userSession.getUser());
                List<Recipe> rec = cookbookService.getRecipesFromCookbook(book);

                model.addAttribute("currentBook", book);
                model.addAttribute("cookbooks", cook);
                model.addAttribute("recipes", rec);
            } else {
                model.addAttribute("currentBook", null);
                model.addAttribute("cookbooks", null);
                model.addAttribute("recipes", null);
            }
        } catch (Exception e) {
            log.info(String.format(
                    "Problem with list cookbooks. Exception: %s",
                    e.getMessage()));

            model.addAttribute(
                    "errorMsgs",
                    Arrays.asList(new String[] { "Wystąpił błąd. Spróbuj ponownie." }));

            return "message";
        }

        return "user/cookbook/list";
    }

    @RequestMapping("management/list")
    public String managementList(Model model) {
        try {
            model.addAttribute("cookbooks",
                    cookbookService.getUsersCookbooks(userSession.getUser()));
        } catch (Exception e) {
            log.info(String.format(
                    "Problem with management list cookbooks. Exception: %s",
                    e.getMessage()));

            model.addAttribute(
                    "errorMsgs",
                    Arrays.asList(new String[] { "Wystąpił błąd. Spróbuj ponownie." }));

            return "message";
        }

        return "user/cookbook/management/list";
    }

    @RequestMapping("list/{bookId}")
    public String list(@PathVariable("bookId")
    Long bookId, Model model) {
        try {
            Cookbook current = cookbookService.getCookBook(bookId);

            if (current != null) {
                if (current.getAuthor().getId() == userSession.getUser()
                        .getId()) {
                    List<Cookbook> cook = cookbookService
                            .getUsersCookbooks(userSession.getUser());
                    List<Recipe> recipes = cookbookService
                            .getRecipesFromCookbook(current);

                    model.addAttribute("currentBook", current);
                    model.addAttribute("cookbooks", cook);
                    model.addAttribute("recipes", recipes);
                } else {
                    model.addAttribute("errorMsgs", Arrays
                            .asList(new String[] { "Nieprawidłowa książka." }));

                    return "forward:user/cookbook/list";
                }
            } else {
                model.addAttribute("errorMsgs", Arrays
                        .asList(new String[] { "Nieprawidłowa książka." }));

                return "forward:user/cookbook/list";
            }
        } catch (Exception ex) {
            log.info(String.format("Problem with cookbook list. Exception: %s",
                    ex.getMessage()));

            model.addAttribute(
                    "errorMsgs",
                    Arrays.asList(new String[] { "Wystąpił błąd. Spróbuj ponownie." }));

            return "message";
        }

        return "user/cookbook/list";
    }
}
